use std::cmp::min;

use async_std::io::{Read, Write};

struct MockTcpStream {
    read_data: Vec<u8>,
    write_data: Vec<u8>,
}

impl Read for MockTcpStream {
    fn poll_read(
        self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
        buf: &mut [u8],
    ) -> std::task::Poll<std::io::Result<usize>> {
        let size = min(self.read_data.len(), buf.len());
        buf[..size].copy_from_slice(&self.read_data[..size]);
        std::task::Poll::Ready(Ok(size))
    }
}

impl Write for MockTcpStream {
    fn poll_close(
        self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<std::io::Result<()>> {
        std::task::Poll::Ready(Ok(()))
    }

    fn poll_flush(
        self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
    ) -> std::task::Poll<std::io::Result<()>> {
        std::task::Poll::Ready(Ok(()))
    }

    fn poll_write(
        self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
        buf: &[u8],
    ) -> std::task::Poll<std::io::Result<usize>> {
        self.get_mut().write_data = buf.to_vec();
        std::task::Poll::Ready(Ok(buf.len()))
    }
}

impl Unpin for MockTcpStream {}

#[async_std::test]
async fn test_handle_connection() {
    use crate::{server::handle_connection, utils::get_resources_path};
    use async_std::fs;

    let mut mock_stream = MockTcpStream {
        read_data: b"GET / HTTP/1.1\r\n".to_vec(),
        write_data: vec![],
    };

    handle_connection(&mut mock_stream).await.unwrap();

    let expected_data = fs::read_to_string(get_resources_path().join("index.html"))
        .await
        .unwrap();
    assert!(&mock_stream.write_data[..].ends_with(expected_data.as_bytes()));
}
